"""
@File    : mock.py
@Create Time: 2025-08-14 9:22
@Description: Mock Server 服务 (Command Line Interface Version)
             - 使用 logging 模块替换 print
             - 接口返回值包含动态信息 (路径, 方法, 时间戳, UUID)
             - 显式添加 Content-Length 响应头
             - 在日志中打印接收到的 POST 数据内容
             - 支持通过命令行参数或环境变量配置 Host 和 Port
             - 默认监听所有接口 (0.0.0.0) 的 9012 端口
"""

import json
import logging
import argparse
import os
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
from datetime import datetime
import uuid

# 配置日志系统，设置日志级别和格式
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)


class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """支持多线程的HTTP服务器类，可以同时处理多个请求"""


class RequestHandler(BaseHTTPRequestHandler):
    """HTTP请求处理器类，用于处理GET、POST等HTTP请求"""

    def _send_dynamic_response(self, method, path, received_data=None):
        """
        发送包含动态信息的JSON响应

        Args:
            method (str): HTTP请求方法 (GET, POST等)
            path (str): 请求路径
            received_data (bytes, optional): 接收到的请求数据
        """
        # 生成唯一的请求ID，用于标识和追踪每个请求
        request_id = str(uuid.uuid4())

        # 构造响应数据
        data = {
            'status_code': 200,  # HTTP状态码
            'message': 'Request processed successfully',  # 响应消息
            'timestamp': datetime.now().isoformat(),  # 当前时间戳
            'id': request_id,  # 唯一请求ID
            'request': {  # 请求相关信息
                'method': method,  # 请求方法
                'path': path  # 请求路径
            }
        }

        # 如果有接收到的数据，则将其添加到响应中
        if received_data is not None:
            # 将接收到的原始数据作为字符串存入响应
            decoded_data = received_data.decode('utf-8') if isinstance(received_data, bytes) else received_data
            data['request']['received_data'] = decoded_data

        # 将响应数据序列化为JSON并编码为字节
        response_bytes = json.dumps(data, ensure_ascii=False).encode('utf-8')

        # 发送HTTP响应
        self.send_response(200)  # 设置HTTP状态码
        self.send_header('Content-Type', 'application/json')  # 设置内容类型为JSON
        self.send_header('Content-Length', str(len(response_bytes)))  # 设置内容长度
        # 为了方便前端调用，添加 CORS 头 (根据评价建议)
        # 注意：* 是不安全的，生产环境应指定具体域名
        self.send_header('Access-Control-Allow-Origin', '*')  # 允许跨域访问
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')  # 允许的HTTP方法
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')  # 允许的请求头
        self.end_headers()  # 结束响应头
        self.wfile.write(response_bytes)  # 发送响应体
        # 记录响应发送日志
        logger.info(f"Sent dynamic response for {method} {path} with ID: {request_id}")

    def do_GET(self):
        """
        处理 GET 请求
        当客户端发送GET请求时会调用此方法
        """
        logger.info(f"Received GET request for path: {self.path}")  # 记录接收到的GET请求
        try:
            # 发送动态响应，包含请求方法和路径
            self._send_dynamic_response('GET', self.path)
        except Exception as e:
            # 记录错误并发送500错误响应
            logger.error(f"Error in GET request: {e}")
            self.send_error(500, f"Internal Server Error: {e}")

    def do_POST(self):
        """处理 POST 请求"""
        logger.info(f"Received POST request for path: {self.path}")

        # 特殊路径用于测试500错误
        if self.path == '/test/500':
            logger.info("Triggering 500 error for testing")
            self._send_error_response(500, "This is a test 500 error response")
            return

        # 特殊路径用于测试异常情况
        if self.path == '/test/exception':
            logger.info("Triggering exception for testing")
            raise Exception("This is a test exception")

        # 原有处理逻辑
        try:
            content_length = int(self.headers.get('Content-Length', 0))
            post_data = self.rfile.read(content_length) if content_length > 0 else b''

            # --- 打印 POST 数据内容 ---
            if post_data:
                try:
                    # 尝试将其作为 JSON 解析并美化打印
                    post_data_str = post_data.decode('utf-8')
                    post_data_json = json.loads(post_data_str)
                    logger.info(f"POST data received (JSON):\n{json.dumps(post_data_json, indent=2, ensure_ascii=False)}")
                except json.JSONDecodeError:
                    # 如果不是 JSON，直接打印原始字符串
                    logger.info(f"POST data received (Raw): {post_data.decode('utf-8')}")
            else:
                logger.info("POST request received with no data.")

            self._send_dynamic_response('POST', self.path, post_data)
        except Exception as e:
            logger.error(f"Error in POST request: {e}")
            self._send_error_response(500, f"Internal Server Error: {e}")

    def _send_error_response(self, code, message):
        """
        发送自定义错误响应（JSON格式）

        Args:
            code (int): HTTP错误码
            message (str): 错误消息
        """
        # 生成唯一的请求ID
        request_id = str(uuid.uuid4())

        # 构造错误响应数据
        error_data = {
            'status_code': code,
            'error': message,
            'timestamp': datetime.now().isoformat(),
            'id': request_id,
            'request': {
                'method': self.command,  # 请求方法 (GET, POST等)
                'path': self.path  # 请求路径
            }
        }

        # 序列化并编码响应
        response_bytes = json.dumps(error_data, ensure_ascii=False).encode('utf-8')

        # 发送错误响应
        self.send_response(code)  # 设置HTTP状态码
        self.send_header('Content-Type', 'application/json')
        self.send_header('Content-Length', str(len(response_bytes)))
        # 添加 CORS 头
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')
        self.end_headers()
        self.wfile.write(response_bytes)

        # 记录错误响应发送
        logger.info(f"Sent error response {code} for {self.command} {self.path} with ID: {request_id}")

    def do_OPTIONS(self):
        """
        处理 OPTIONS 请求
        主要用于处理CORS预检请求
        """
        self.send_response(200)  # 发送200状态码
        self.send_header('Access-Control-Allow-Origin', '*')  # 允许跨域访问
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')  # 允许的HTTP方法
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')  # 允许的请求头
        self.end_headers()  # 结束响应头

    def log_message(self, format, *args):
        """
        覆盖默认的日志记录方法
        禁用BaseHTTPRequestHandler默认的日志记录格式，使用我们自己的logger
        """
        pass  # 使用我们自己的 logger


def parse_arguments():
    """
    解析命令行参数
    支持通过命令行参数或环境变量配置服务器的主机和端口

    Returns:
        argparse.Namespace: 解析后的命令行参数
    """
    # 创建参数解析器
    parser = argparse.ArgumentParser(description="A simple mock HTTP server.")

    # 添加主机参数
    parser.add_argument(
        "--host", "-H",
        type=str,
        default=os.environ.get("MOCK_SERVER_HOST", "0.0.0.0"),  # 默认从环境变量或 '0.0.0.0' 获取
        help="Host to bind the server to (default: 0.0.0.0 or value of MOCK_SERVER_HOST env var)"
    )

    # 添加端口参数
    parser.add_argument(
        "--port", "-p",
        type=int,
        default=int(os.environ.get("MOCK_SERVER_PORT", 9012)),  # 默认从环境变量或 9012 获取
        help="Port to bind the server to (default: 9012 or value of MOCK_SERVER_PORT env var)"
    )
    return parser.parse_args()  # 返回解析后的参数


def main():
    """
    主函数，程序入口点
    负责解析参数、启动服务器和处理服务器关闭
    """
    # 解析命令行参数
    args = parse_arguments()
    host = args.host
    port = args.port

    # 设置服务器地址
    # 使用 ('', port) 也可以绑定到所有接口，但显式使用 '0.0.0.0' 更清晰
    # 如果 host 是 '0.0.0.0' 或 ''，则监听所有接口
    server_address = (host, port)
    # 创建多线程HTTP服务器实例
    server = ThreadedHTTPServer(server_address, RequestHandler)

    # 记录服务器启动信息
    logger.info("====== Mock Server with CLI Main Begin ======")
    logger.info("Starting server, listening at http://%s:%s", host if host else '0.0.0.0', port)
    logger.info("Server will run persistently. Press Ctrl+C to stop.")

    try:
        # 启动服务器，持续运行直到被中断
        server.serve_forever()
    except KeyboardInterrupt:
        # 处理Ctrl+C中断信号，优雅关闭服务器
        logger.info("Received interrupt signal. Shutting down server gracefully...")
        server.shutdown()  # 关闭服务器
        server.server_close()  # 关闭服务器套接字
        logger.info("Server stopped.")  # 记录服务器已停止


if __name__ == '__main__':
    # 程序入口点
    main()

